'use strict';
// 引入阿里云IoT SDK，用于调用阿里云IoT相关API
const { IoTClient, QueryDeviceDetailRequest, QueryDevicePropertyDataRequest } = require('@alicloud/iot20180120');
// 引入阿里云STS SDK模块
const STS_MODULE = require('@alicloud/sts20150401'); 
const { AssumeRoleRequest } = STS_MODULE; // 从模块中解构出 AssumeRoleRequest

// 引入阿里云OpenAPI Client的Config，用于STS客户端和IoT客户端的配置
const { Config: OpenApiConfig } = require('@alicloud/openapi-client');
// 引入阿里云Tea工具的RuntimeOptions，用于配置API请求的运行时选项
const { RuntimeOptions } = require('@alicloud/tea-util');

// === 关键配置参数 ===
const CONFIG = {
  // 数据查询窗口，单位毫秒，这里是1.5分钟
  QUERY_WINDOW: 90000,
  // 平台数据延迟，单位毫秒，用于调整查询的结束时间，避免查到还未完全同步的数据
  PLATFORM_DELAY: 10000,
  // 设备相关配置
  DEVICE_CONFIG: {
    // 您的产品Key
    productKey: 'k25es2SPWFj',
    // 您的设备名称
    deviceName: 'device1',
    // 要查询的设备属性列表及其配置
    properties: [
      { identifier: 'LightLux', type: 'int', range: [0, 4095] }, // 光照度，整数类型，范围0-4095
      { identifier: 'Humidity', type: 'float', range: [0, 100] }, // 湿度，浮点类型，范围0-100
      { identifier: 'soilHumidity', type: 'int', range: [0, 4095], convertToPercent: true }, // 土壤湿度，整数类型，范围0-4095，需要转换为百分比
      { identifier: 'temperature', type: 'float', range: [-40, 80] } // 温度，浮点类型，范围-40-80
    ]
  }
};

// RAM角色的ARN (Amazon Resource Name)，用于STS服务扮演
// !!! 替换为你在阿里云RAM控制台创建的，并赋予IoT访问权限的RAM角色的ARN !!!
const RAM_ROLE_ARN = 'acs:ram::1818129816751559:role/1488578273636685';
// 扮演RAM角色时的会话名称，用于审计追踪
const ROLE_SESSION_NAME = 'uniCloudIoTCall'; 

// Node.js兼容性处理：如果当前环境（如旧版Node.js）未提供TextDecoder/TextEncoder，则尝试引入util模块进行 Polyfill
if (typeof global.TextDecoder === 'undefined') {
  try {
    const util = require('util');
    global.TextDecoder = util.TextDecoder;
    global.TextEncoder = util.TextEncoder;
  } catch (e) {
    // 如果引入失败，则发出警告
    console.warn('TextDecoder/TextEncoder不可用:', e.message);
  }
}

/**
 * 数值转换与验证函数
 * 根据属性配置对原始值进行类型转换、范围校验，并处理特殊转换（如土壤湿度转百分比）
 * @param {string|number} rawValue - 原始数值
 * @param {object} prop - 属性配置对象，包含identifier, type, range, convertToPercent等
 * @returns {number|null} 转换并验证后的数值，如果无效则返回null
 */
const convertAndValidateValue = (rawValue, prop) => {
  try {
    let numValue = rawValue;
    // 如果原始值是字符串，尝试解析出数字
    if (typeof rawValue === 'string') {
      // 移除所有非数字、非小数点、非负号的字符，然后解析为浮点数
      numValue = parseFloat(rawValue.replace(/[^\d.-]/g, ''));
    }
    // 根据属性类型进行整数或浮点数转换
    let value = prop.type === 'int' ? parseInt(numValue) : numValue;
    // 如果是土壤湿度且需要转换为百分比，则进行转换
    if (prop.convertToPercent && prop.identifier === 'soilHumidity') {
      const [min, max] = prop.range;
      // 将原始值映射到0-100的百分比范围，并四舍五入
      value = Math.round((value / (max - min)) * 100);
    }
    // 范围校验
    if (prop.range && (value < prop.range[0] || value > prop.range[1])) {
      console.warn(`数值超出范围: ${prop.identifier}=${value}`);
      return null; // 超出范围则返回null
    }
    // 检查是否为NaN（Not-a-Number），如果是则返回null
    return isNaN(value) ? null : value;
  } catch (error) {
    // 捕获转换过程中的错误
    console.error(`数值转换错误(${prop.identifier}):`, error);
    return null;
  }
};

// 云函数入口函数
exports.main = async (event, context) => {
  const startTime = Date.now(); // 记录函数开始执行时间
  // 初始化结果对象
  const result = {
    code: 200, // 默认成功码
    message: 'success', // 默认成功信息
    data: {}, // 存储查询到的设备属性数据
    timestamps: {}, // 存储查询到数据的对应时间戳
    meta: {
      startTime: new Date(startTime).toISOString() // 记录开始时间（ISO格式）
    }
  };

  try {
    console.log(`==== 开始执行云函数 [${new Date().toISOString()}] ====`);
    console.log('process.env (Before Cleanup):', process.env); // 打印原始环境变量，用于调试

    // **强制清理可能影响阿里云SDK读取的环境变量**
    // 阿里云SDK会优先读取这些环境变量，如果存在可能导致使用错误的凭证或配置
    delete process.env.ALIBABA_CLOUD_ACCESS_KEY_ID;
    delete process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET;
    delete process.env.ALIBABA_CLOUD_SECURITY_TOKEN;
    delete process.env.FC_REGION; // 删除云函数平台的Region环境变量，避免与IoT服务区域混淆
    delete process.env.IOT_INSTANCE_ID; // 再次确认清理IotInstanceId，防止误用
    delete process.env.IOT_INSTANCEID;
    delete process.env.iot_instance_id;

    console.log('process.env (After Cleanup):', process.env); // 打印清理后环境变量，用于调试

    let tempAkId, tempAkSecret, tempToken; // 声明临时凭证变量

    try {
        // 创建STS客户端配置对象
        const stsConfig = new OpenApiConfig({
            endpoint: 'sts.aliyuncs.com' // STS服务在全球所有区域都使用这个公共Endpoint
        });

        // 创建STS客户端实例
        const stsClient = new STS_MODULE.Client(stsConfig); 

        // 构建 AssumeRoleRequest 请求对象
        const assumeRoleRequest = new AssumeRoleRequest({
            RoleArn: RAM_ROLE_ARN,
            RoleSessionName: ROLE_SESSION_NAME,
            DurationSeconds: 3600 // 设置临时凭证的有效期为 3600 秒 (1小时)
        });

        // 创建运行时选项
        const runtime = new RuntimeOptions({});

        // 调用 assumeRoleWithOptions 扮演RAM角色，获取临时凭证
        const assumeRoleResponse = await stsClient.assumeRoleWithOptions(assumeRoleRequest, runtime);
        console.log('AssumeRole Response:', JSON.stringify(assumeRoleResponse, null, 2));

        // 检查AssumeRole响应是否成功并获取凭证
        if (assumeRoleResponse && assumeRoleResponse.body && assumeRoleResponse.body.credentials) {
            tempAkId = assumeRoleResponse.body.credentials.accessKeyId;
            tempAkSecret = assumeRoleResponse.body.credentials.accessKeySecret;
            tempToken = assumeRoleResponse.body.credentials.securityToken;
        } else {
            console.error('AssumeRole failed, no credentials received:', assumeRoleResponse);
            throw new Error('Failed to get temporary credentials for IoT access');
        }

    } catch (assumeRoleError) {
        // 捕获扮演RAM角色过程中的错误
        console.error('Error assuming RAM role:', assumeRoleError);
        result.code = 500;
        result.error = `Failed to get temporary credentials for IoT access: ${assumeRoleError.message}`;
        return result; // 扮演角色失败，直接返回错误结果
    }

    // 使用STS获取到的临时凭证初始化IoT客户端 (替换原有的POP Core客户端)
    const iotConfig = new OpenApiConfig({
        accessKeyId: tempAkId,        // 使用临时AccessKeyId
        accessKeySecret: tempAkSecret,  // 使用临时AccessKeySecret
        securityToken: tempToken,     // 使用临时SecurityToken
        endpoint: 'iot.cn-shanghai.aliyuncs.com', // IoT服务Endpoint，确保区域一致
    });
    const client = new IoTClient(iotConfig);
    const runtimeOptions = new RuntimeOptions({}); // 用于IoTClient方法的运行时选项

    // 时间范围计算（UTC毫秒时间戳）
    // IoT数据查询需要UTC时间戳，不要手动加8小时偏移
    const now = Date.now();
    const endTime = now - CONFIG.PLATFORM_DELAY; // 结束时间为当前时间减去平台延迟
    const startTimeQuery = endTime - CONFIG.QUERY_WINDOW; // 开始时间为结束时间减去查询窗口
    console.log('查询时间范围(UTC):', {
      start: new Date(startTimeQuery).toISOString(),
      end: new Date(endTime).toISOString(),
      duration: `${CONFIG.QUERY_WINDOW/1000}秒` // 查询时长
    });

    // 权限检查：首先调用QueryDeviceDetail验证RAM角色是否具有IoT服务的访问权限
    try {
      const request = new QueryDeviceDetailRequest({
        ProductKey: CONFIG.DEVICE_CONFIG.productKey,
        DeviceName: CONFIG.DEVICE_CONFIG.deviceName,
      });
      console.log('调用 queryDeviceDetailWithOptions 参数:', request);
      // 使用 IoTClient 的方法代替 Core.request
      const response = await client.queryDeviceDetailWithOptions(request, runtimeOptions);
      console.log(`权限验证通过: ${response.requestId}`);
    } catch (testError) {
      // 权限验证失败时捕获错误并返回详细信息
      console.error('权限验证失败:', testError);
      let errorDetails = `错误码: ${testError.code || '未知'}, 信息: ${testError.message || '无详细信息'}`;
      let debugInfo = `
AccessKeyId (from STS): ${tempAkId}
Device: ${CONFIG.DEVICE_CONFIG.productKey}/${CONFIG.DEVICE_CONFIG.deviceName}
API Params: ${JSON.stringify({
        ProductKey: CONFIG.DEVICE_CONFIG.productKey,
        DeviceName: CONFIG.DEVICE_CONFIG.deviceName,
        RegionId: "cn-shanghai"
      })}
      `;
      let solution = `解决方案:
1. 确认RAM角色(${RAM_ROLE_ARN})信任策略是否正确配置了uniCloud云函数的Service Principal ARN。
   （注意：uniCloud云函数的Service Principal ARN获取方式可能特殊，需查阅uniCloud文档）
2. 检查RAM角色是否已附加正确的IoT访问权限策略（确保策略的Resource ARN覆盖了你的IoT资源，或者暂时设置为"*"进行测试）。
3. 检查RAM角色ARN在云函数代码中是否正确（即RAM_ROLE_ARN常量的值）。
4. 确认IoT实例、产品、设备确实在cn-shanghai区域。
      `;
      result.code = 403; // 设置为权限拒绝码
      result.error = `${errorDetails}\n${debugInfo}\n${solution}`;
      return result; // 权限验证失败后直接返回，不再执行后续操作
    }

    // 并行查询所有配置的设备属性数据
    const results = await Promise.all(CONFIG.DEVICE_CONFIG.properties.map(async (prop) => {
      try {
        const request = new QueryDevicePropertyDataRequest({
          ProductKey: CONFIG.DEVICE_CONFIG.productKey,
          DeviceName: CONFIG.DEVICE_CONFIG.deviceName,
          Identifier: prop.identifier, // 属性标识符
          StartTime: startTimeQuery,  // 查询开始时间
          EndTime: endTime,           // 查询结束时间
          Asc: 0,                   // 降序排列（最新数据在前）
          PageSize: 10,               // 每页返回10条数据
          // RegionId: "cn-shanghai" // RegionId 通常在客户端配置中指定，或者在某些请求中可以覆盖
        });
        console.log('调用 queryDevicePropertyDataWithOptions 参数:', request);
        // 使用 IoTClient 的方法代替 Core.request
        const response = await client.queryDevicePropertyDataWithOptions(request, runtimeOptions);
        // 检查API返回数据结构是否符合预期
        if (!response || !response.body || !response.body.list || !response.body.list.propertyInfo) { // 修正响应路径
          console.warn(`API返回数据结构异常:`, response);
          return {
            identifier: prop.identifier,
            error: 'API返回数据结构异常',
            code: 'API_DATA_ERROR'
          };
        }
        const records = response.body.list.propertyInfo; // 修正响应路径
        // 遍历查询到的数据记录，找到第一个有效值
        for (const record of records) {
          const value = convertAndValidateValue(record.value, prop); // 修正record.Value为record.value
          if (value !== null) {
            // 如果找到有效值，则返回
            return {
              identifier: prop.identifier,
              value,
              timestamp: record.time // 修正record.Time为record.time
            };
          }
        }
        // 如果遍历完所有记录都没有找到有效值
        console.warn(`无有效数据: ${prop.identifier}, 返回默认值`);
        return {
          identifier: prop.identifier,
          value: 0, // 可以根据业务逻辑返回一个默认值或抛出错误
          timestamp: Date.now()
        };
      } catch (error) {
        // 捕获单个属性查询失败的错误
        console.error(`查询 ${prop.identifier} 失败:`, error);
        return {
          identifier: prop.identifier,
          error: `查询失败: ${error.code || 'API_ERROR'} - ${error.message || ''}`,
          code: error.code || '500'
        };
      }
    }));

    // 处理所有属性的查询结果
    let validDataCount = 0;
    result.errors = {}; // 初始化错误存储对象
    results.forEach(item => {
      if (item.value !== undefined) {
        // 如果有有效值，则存储到result.data和result.timestamps
        result.data[item.identifier] = item.value;
        result.timestamps[item.identifier] = item.timestamp;
        validDataCount++;
      } else if (item.error) {
        // 如果有错误，则存储到result.errors
        result.errors[item.identifier] = item.error;
      }
    });

    // 根据数据获取情况调整返回码和消息
    if (validDataCount === 0) {
      result.code = 503; // 服务不可用，表示没有获取到任何有效数据
      result.message = '无有效数据';
    } else if (validDataCount < CONFIG.DEVICE_CONFIG.properties.length) {
      result.code = 206; // 部分内容，表示部分数据缺失
      result.message = `部分数据缺失 (${validDataCount}/4)`;
    }
  } catch (globalError) {
    // 捕获全局未处理的异常
    console.error('全局错误:', globalError);
    result.code = 500; // 服务器内部错误
    result.error = `服务器错误: ${globalError.message}`;
  }
  result.meta.endTime = new Date().toISOString(); // 记录结束时间
  result.meta.executionTime = `${Date.now() - startTime}ms`; // 计算执行时间
  console.log(`==== 结束执行 (${result.meta.executionTime}) ====`);
  // 打印最终结果概要
  console.log('最终结果:', {
    code: result.code,
    message: result.message,
    dataCount: Object.keys(result.data).length,
    errorCount: Object.keys(result.errors).length
  });
  return result; // 返回最终结果
};